/***************************************************************************//**
 * @file stateMachine.c
 * @brief for common stateMachine
 * @author ze .
 * @date  2022/7/03.
 * @copyright Copyright 
 ******************************************************************************/

#include "stateMachine.h"

static void goToErrorState( struct stateMachine *stateMachine, struct event *const event );
static struct transition *getTransition( struct stateMachine *stateMachine, struct state *state, struct event *const event );

void stateM_init( struct stateMachine *fsm, struct state *initialState, struct state *errorState ,void* data)
{
   if ( !fsm )
      return;

   fsm->currentState = initialState;
   fsm->previousState = NULL;
   fsm->errorState = errorState;
   fsm->ctrlData = data;
}

int stateM_handleEvent( struct stateMachine *fsm, struct event *event )
{

   int ret = stateM_stateChanged;
   struct state *nextState = NULL;

   if ( !fsm || !event )
      return stateM_errArg;
#if 0
   if ( !fsm->currentState )
   {
      goToErrorState( fsm, event );
      return stateM_errorStateReached;
   }

   if ( !fsm->currentState->numTransitions )
      return stateM_noStateChange;
#endif

   {
      struct transition *transition = getTransition( fsm, fsm->currentState, event );

      /* If there were no transitions for the given event for the current state */
      if ( !transition )
      {
         return stateM_noStateChange; //the the event does't meet.
      }

      /* A transition must have a next state defined. If the user has not defined the next state, go to error state: */
      if ( !transition->nextState )
      {
         goToErrorState( fsm, event );
         return stateM_errorStateReached;
      }

      nextState = transition->nextState;

      /* Run exit action only if the current state is left (only if it does
       * not return to itself): */
      // if ( nextState != fsm->currentState && fsm->currentState->exitAction )
      // {
      //    fsm->currentState->exitAction( fsm->currentState->data, event );
      // }

      /* Run transition action (if any): */
      if ( transition->action )
      {
         if(transition->action(fsm, event))
         {
            ret = stateM_stateNextContinue; //直接跳转到下一个状态执行
         }
      }

      /* Call the new state's entry action if it has any (only if state does
       * not return to itself): */
      // if ( nextState != fsm->currentState && nextState->entryAction )
      // {
      //    nextState->entryAction( nextState->data, event );
      // }

      fsm->previousState = fsm->currentState;
      fsm->currentState = nextState;

      /* If the state returned to itself: */
      if ( fsm->currentState == fsm->previousState )
         return stateM_stateLoopSelf;
#if 0  
      if ( fsm->currentState == fsm->errorState )
         return stateM_errorStateReached;

      /* If the new state is a final state, notify user that the state
       * machine has stopped: */
      if ( !fsm->currentState->numTransitions )
         return stateM_finalStateReached;
#endif
   }

   return ret;
}

struct state *stateM_currentState( struct stateMachine *fsm )
{
   if ( !fsm )
      return NULL;

   return fsm->currentState;
}

struct state *stateM_previousState( struct stateMachine *fsm )
{
   if ( !fsm )
      return NULL;

   return fsm->previousState;
}


static void goToErrorState( struct stateMachine *fsm,
      struct event *const event )
{
   fsm->previousState = fsm->currentState;
   fsm->currentState = fsm->errorState;

   // if ( fsm->currentState && fsm->currentState->entryAction )
   //    fsm->currentState->entryAction( fsm->currentState->data, event );
}

static struct transition *getTransition( struct stateMachine *fsm,
      struct state *state, struct event *const event )
{
   size_t i;

   for ( i = 0; i < state->numTransitions; ++i )
   {
      struct transition *t = &state->transitions[ i ];

      /* A transition for the given event has been found: */
      if ( t->eventType == event->type )
      {
         if ( !t->guard )
            return t;
         /* If transition is guarded, ensure that the condition is held: */
         else if ( t->guard(fsm , t->condition, event ) )
            return t;
      }
   }

   /* No transitions found for given event for given state: */
   return NULL;
}

bool stateM_stopped( struct stateMachine *stateMachine )
{
   if ( !stateMachine )
      return true;

   return stateMachine->currentState->numTransitions == 0;
}
